// Connect.h : Declaration of the CConnect

#pragma once
#include "resource.h"       // main symbols

using namespace AddInDesignerObjects;
//using namespace EnvDTE;
using namespace EnvDTE80;
using namespace Microsoft_VisualStudio_CommandBars;
using namespace VCProjectEngineLibrary;

void ConnectAndUnregisterAllCommands();

class CTestSuiteTool;

class CConnect;
typedef IDispEventImpl<2, CConnect, &__uuidof(EnvDTE::_dispBuildEvents), &EnvDTE::LIBID_EnvDTE, 8, 0> BuildEventImpl;
typedef IDispEventImpl<1, CConnect, &__uuidof(EnvDTE::_dispDebuggerEvents), &EnvDTE::LIBID_EnvDTE, 8, 0> DebuggerEventImpl;

/// <summary>The object for implementing an Add-in.</summary>
/// <seealso class='IDTExtensibility2' />
class ATL_NO_VTABLE CConnect : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CConnect, &CLSID_Connect>,
	public IDispatchImpl<EnvDTE::IDTCommandTarget, &__uuidof(EnvDTE::IDTCommandTarget), &EnvDTE::LIBID_EnvDTE, 8, 0>,
	public IDispatchImpl<_IDTExtensibility2, &IID__IDTExtensibility2, &LIBID_AddInDesignerObjects, 1, 0>,
	public DebuggerEventImpl,
	public BuildEventImpl
{
public:
	/// <summary>Implements the constructor for the Add-in object. Place your initialization code within this method.</summary>
	CConnect();
	virtual ~CConnect();

//DECLARE_REGISTRY_RESOURCEID(IDR_ADDIN)
	static HRESULT WINAPI UpdateRegistry( BOOL bRegister )
	{
		_ATL_REGMAP_ENTRY rgMap[2];
		memset(rgMap, '\0', sizeof(_ATL_REGMAP_ENTRY ) * 2);

		WCHAR szModule[_MAX_PATH] = {0};
		GetModuleFileName(_AtlModule.GetResourceInstance(), szModule, _MAX_PATH);
		PathRemoveFileSpec(szModule);

		USES_CONVERSION;
		rgMap[0].szKey = OLESTR("MODULE_PATH");
		rgMap[0].szData = T2OLE(szModule);

		return _AtlModule.UpdateRegistryFromResource(IDR_ADDIN, bRegister, rgMap);
	}

DECLARE_NOT_AGGREGATABLE(CConnect)


BEGIN_COM_MAP(CConnect)
	COM_INTERFACE_ENTRY(IDTExtensibility2)
	COM_INTERFACE_ENTRY(IDTCommandTarget)
	COM_INTERFACE_ENTRY2(IDispatch, IDTExtensibility2)
END_COM_MAP()


	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}
	
	void FinalRelease() 
	{
	}

public:
//IDTExtensibility2 implementation:

	/// <summary>Implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded.</summary>
	/// <param term='application'>Root object of the host application.</param>
	/// <param term='connectMode'>Describes how the Add-in is being loaded.</param>
	/// <param term='addInInst'>Object representing this Add-in.</param>
	/// <seealso class='IDTExtensibility2' />
	STDMETHOD(OnConnection)(IDispatch * Application, ext_ConnectMode ConnectMode, IDispatch *AddInInst, SAFEARRAY **custom);

	/// <summary>Implements the OnDisconnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being unloaded.</summary>
	/// <param term='disconnectMode'>Describes how the Add-in is being unloaded.</param>
	/// <param term='custom'>Array of parameters that are host application specific.</param>
	/// <seealso class='IDTExtensibility2' />
	STDMETHOD(OnDisconnection)(ext_DisconnectMode RemoveMode, SAFEARRAY **custom );

	/// <summary>Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. Receives notification when the collection of Add-ins has changed.</summary>
	/// <param term='custom'>Array of parameters that are host application specific.</param>
	/// <seealso class='IDTExtensibility2' />	
	STDMETHOD(OnAddInsUpdate)(SAFEARRAY **custom );

	/// <summary>Implements the OnStartupComplete method of the IDTExtensibility2 interface. Receives notification that the host application has completed loading.</summary>
	/// <param term='custom'>Array of parameters that are host application specific.</param>
	/// <seealso class='IDTExtensibility2' />
	STDMETHOD(OnStartupComplete)(SAFEARRAY **custom );

	/// <summary>Implements the OnBeginShutdown method of the IDTExtensibility2 interface. Receives notification that the host application is being unloaded.</summary>
	/// <param term='custom'>Array of parameters that are host application specific.</param>
	/// <seealso class='IDTExtensibility2' />
	STDMETHOD(OnBeginShutdown)(SAFEARRAY **custom );

	//IDTCommandTarget implementation:
	STDMETHOD(QueryStatus)(BSTR CmdName, EnvDTE::vsCommandStatusTextWanted NeededText, EnvDTE::vsCommandStatus *StatusOption, VARIANT *CommandText);
	STDMETHOD(Exec)(BSTR CmdName, EnvDTE::vsCommandExecOption ExecuteOption, VARIANT *VariantIn, VARIANT *VariantOut, VARIANT_BOOL *Handled);
	
	void PrintToOutputMessage(LPCTSTR lpszMessage);
	void PrintToOutput(LPCTSTR format, BOOL bNewLine = TRUE, ...);
	static HRESULT FindToolbarByName(_CommandBars* pCommandBars, LPCWSTR szToolbarName, CommandBar** pOut);

public:
	HRESULT SetSink();
	void RemoveSink();

	BEGIN_SINK_MAP(CConnect)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 1, OnEnterRunMode)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 2, OnEnterDesignMode)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 3, OnEnterBreakMode)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 4, OnExceptionThrown)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 5, OnExceptionNotHandled)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispDebuggerEvents), 6, OnContextChanged)

		SINK_ENTRY_EX(2, __uuidof(EnvDTE::_dispBuildEvents), 3, OnBuildBegin)
		SINK_ENTRY_EX(2, __uuidof(EnvDTE::_dispBuildEvents), 4, OnBuildDone)
		SINK_ENTRY_EX(2, __uuidof(EnvDTE::_dispBuildEvents), 5, OnBuildProjConfigBegin)
		SINK_ENTRY_EX(2, __uuidof(EnvDTE::_dispBuildEvents), 6, OnBuildProjConfigDone)
	END_SINK_MAP()

	void __stdcall OnEnterRunMode(EnvDTE::dbgEventReason Reason);
	void __stdcall OnEnterDesignMode(EnvDTE::dbgEventReason Reason);
	void __stdcall OnEnterBreakMode(EnvDTE::dbgEventReason Reason, EnvDTE::dbgExecutionAction* ExecutionAction);
	void __stdcall OnExceptionThrown(BSTR ExceptionType, BSTR Name, long Code, BSTR Description, EnvDTE::dbgExceptionAction* ExceptionAction);
	void __stdcall OnExceptionNotHandled(BSTR ExceptionType, BSTR Name, long Code, BSTR Description, EnvDTE::dbgExceptionAction* ExceptionAction);
	void __stdcall OnContextChanged(EnvDTE::Process* NewProcess, EnvDTE::Program* NewProgram, EnvDTE::Thread* NewThread, EnvDTE::StackFrame* NewStackFrame);

	//[id(0x00000003)]
	void __stdcall OnBuildBegin(EnvDTE::vsBuildScope Scope, EnvDTE::vsBuildAction Action);
	//[id(0x00000004)]
	void __stdcall OnBuildDone(EnvDTE::vsBuildScope Scope, EnvDTE::vsBuildAction Action);
	//[id(0x00000005)]
	void __stdcall OnBuildProjConfigBegin(BSTR Project, BSTR ProjectConfig, BSTR Platform, BSTR SolutionConfig);
	//[id(0x00000006)]
	void __stdcall OnBuildProjConfigDone(BSTR Project, BSTR ProjectConfig, BSTR Platform, BSTR SolutionConfig, VARIANT_BOOL Success);

public:
	struct CommandInfo
	{
		LPCWSTR m_name;
		LPCTSTR m_keyStr;
		bool    m_hasIcon;
		bool    m_justText;
		DWORD   m_bitmapID;
		DWORD   m_cmdID;
	};

protected:
	static int myMessageBox(UINT uID, UINT uType = MB_OK);
	static int myMessageBox(LPCTSTR str, UINT uType = MB_OK);
	static wstring myLoadString(UINT uID);
	static BOOL myExtractSubString(wstring& rString, LPCTSTR lpszFullString, int iSubString, TCHAR chSep);
	friend class CTestSuiteTool;

private:
	CComPtr<DTE2> m_pDTE;
	CComPtr<EnvDTE::AddIn> m_pAddInInstance;
	CComPtr<EnvDTE::OutputWindowPane> m_pOutputWindowPane;
	CTestSuiteTool* m_pTestSuite;
	CComPtr<EnvDTE::_DebuggerEvents> m_pDebugEvents;
	CComPtr<EnvDTE::_BuildEvents> m_pBuildEvents;
};

OBJECT_ENTRY_AUTO(__uuidof(Connect), CConnect)
